package com.hmall.gateway.filter;

import cn.hutool.core.collection.CollUtil;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.units.qual.A;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
//导入配置Properties设置的属性
@EnableConfigurationProperties(AuthProperties.class)
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter {
    //这是字符串匹配
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    //导入配置
    private final AuthProperties authProperties;
    //导入jwt工具
    private final JwtTool jwtTool;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.先拿到请求,判断是否是需要被放行路径
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getPath().toString();
        //然后我们判断是否是属于我们放行的路径,根据配置的和我们请求上的路径
        boolean contain = isContain(path, authProperties.getExcludePaths());
        if(contain){
            //包含就直接放行
            return chain.filter(exchange);
        }
        //2,走到这说明不是被放行的路径,我们再判断是否有token
        //从请求头里面拿
        //因为我们有多个请求,所以是带s的,又因为我们请求的键可以重复,所以返回值是一个数组,但是我们清除只有一个
        List<String> headers  = request.getHeaders().get("authorization");
        if(CollUtil.isEmpty(headers )){
            //为空的话说明没有登录,我们返回401,注意这不是之前的过滤器了,不同
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //然后我们不继承往下走了
            return response.setComplete();
        }
        //3,说明有token,我们解析,但是解析的时候可能有异常,我们try一下
        //至于为什么要写null呢,因为我们在try里面定义的可能不生效.所以要定义在外面
        Long userId=null;

        try {
           userId = jwtTool.parseToken(headers.get(0));
        } catch (Exception e) {
            //有异常直接返回401并且终止
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //然后我们不继承往下走了
            return response.setComplete();
        }
        //4.说明程序没有问题把id放进去

        String userInfo = userId.toString();
        exchange.mutate().request(builder -> builder.header("user-info",userInfo)).build();
       return chain.filter(exchange);


    }

    public boolean isContain(String path, List<String> excludePaths) {
        //遍历传来的模版字符串跟我们请求里面的进行比较
        for (String excludePath : excludePaths) {
            if (antPathMatcher.match(excludePath, path)) {
                //包含我们就就直接返回true了,就不用再去往下了
                return true;
            }
        }
          //走到这说明根本就没有
        return false;
    }
}
